package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.repository;

import com.alibaba.algo.cooperation.common.BaseResult;
import com.alibaba.algo.cooperation.feign.service.UserFeignService;
import com.alibaba.algo.cooperation.feign.vo.req.SelectUserInfoReqVO;
import com.alibaba.algo.cooperation.feign.vo.res.RpcUserInfoVO;
import com.alibaba.algo.cooperation.feign.vo.res.UserOrgResVO;
import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Lists;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.ExpressionCmd;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.ExpressionUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.utils.UUIDGenerator;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowCustomNodeTitleEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowTitleExpression;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowTitleExpressionResult;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowTitleExpressionResultRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowTitleExpressionDAO;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowTitleExpressionResultDAO;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.common.api.variable.VariableContainer;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author: lzb
 * @date: 2021/11/9 17:04
 */
@Slf4j
@Service
public class FlowTitleExpressionResultRepositoryImpl implements FlowTitleExpressionResultRepository {

    public static final String CUR_DATE = "YYYY-MM-dd";
    public static final String CUR_TIME = "YYYY-MM-dd HH:mm:ss";

    @Autowired
    private UserFeignService userFeignService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    private FlowTitleExpressionResultDAO flowTitleExpressionResultDAO;

    @Autowired
    private FlowTitleExpressionDAO flowTitleExpressionDAO;

    @Autowired
    private ManagementService managementService;

    @Override
    public String getTitleExpressionResultByProcessInstanceIdAndActivityId(String processInstanceId, String activityId) {
        String expressionResult = "";
        try {
            String result = flowTitleExpressionResultDAO.getTitleExpressionResultByProcessInstanceIdAndActivityId(processInstanceId, activityId);
            expressionResult = verificationString(result) ? result : flowTitleExpressionResultDAO.getTitleExpressionResultByProcessInstanceId(processInstanceId);
        } catch (Exception e) {
            log.warn("流程id：{}自定义函数解析失败：{}", processInstanceId, e.getMessage());
        }
        return expressionResult;
    }

    /**
     * @param deployId 部署ID
     */
    @Override
    public void batchInsert(String deployId, ExecutionEntity executionEntity) {
        //流程实例id
        String processInstanceId = executionEntity.getProcessInstanceId();
        //拟稿人id
        String initiatorId = executionEntity.getVariable("assigned_apply_initiator").toString();
        FlowTitleExpression flowTitleExpression = flowTitleExpressionDAO.getFlowTitleExpressionByDeployId(deployId);
        if (!Objects.isNull(flowTitleExpression)) {
            FlowTitleExpressionResult flowTitleExpressionResult = new FlowTitleExpressionResult();
            flowTitleExpressionResult.setDeployId(deployId);
            flowTitleExpressionResult.setResult(expressionResult(flowTitleExpression.getExpression(), getUserInfoVO(initiatorId), executionEntity));
            flowTitleExpressionResult.setProcessInstanceId(processInstanceId);
            flowTitleExpressionResultDAO.insertTitleExpressionResult(flowTitleExpressionResult);
        }
    }


    public String expressionResult(String expression, RpcUserInfoVO rpcUserInfoVO, VariableContainer variableContainer) {
        if (StringUtils.isBlank(expression)) {
            return StringUtil.EMPTY_STRING;
        }
        List<String> expressionList = Arrays.asList(expression.split(","));
        if (CollectionUtils.isEmpty(expressionList)) {
            return StringUtil.EMPTY_STRING;
        }
        List<String> resultList = Lists.newLinkedList();
        //用户组织
        //organizationId、organizationName、userEmail、userLoginName、userName、userId、userMobile
        //日期
        //@{datetime}、@{date}、@{month}、@{year}、@{day}、@{week}、@{quarter}

        for (String exp : expressionList) {
            if (Objects.equals(exp, FlowCustomNodeTitleEnum.ORGANIZATION_ID.getName())) {
                if (!CollectionUtils.isEmpty(rpcUserInfoVO.getOrgList())) {
                    String orgIdList = rpcUserInfoVO.getOrgList().stream().map(
                            org -> String.valueOf(org.getOrgId())).collect(Collectors.joining(","));
                    resultList.add(orgIdList);
                } else {
                    resultList.add(FlowCustomNodeTitleEnum.ORGANIZATION_ID.getName());
                }
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.ORGANIZATION_NAME.getName())) {
                if (CollectionUtils.isEmpty(rpcUserInfoVO.getOrgList())) {
                    resultList.add(FlowCustomNodeTitleEnum.ORGANIZATION_NAME.getName());
                } else {
                    String orgNameList = rpcUserInfoVO.getOrgList().stream().map(
                            UserOrgResVO::getOrgName).collect(Collectors.joining(","));
                    resultList.add(orgNameList);
                }
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.USER_EMAIL.getName())) {
                resultList.add(verificationString(rpcUserInfoVO.getEmail()) ?
                        rpcUserInfoVO.getEmail() : FlowCustomNodeTitleEnum.USER_EMAIL.getName());
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.USER_LOGIN_NAME.getName())) {
                resultList.add(rpcUserInfoVO.getUserAccount());
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.USER_NAME.getName())) {
                resultList.add(verificationString(rpcUserInfoVO.getUserName()) ?
                        rpcUserInfoVO.getUserName() : FlowCustomNodeTitleEnum.USER_NAME.getName());
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.USER_ID.getName())) {
                resultList.add(String.valueOf(rpcUserInfoVO.getUserId()));
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.USER_MOBILE.getName())) {
                resultList.add(verificationString(rpcUserInfoVO.getMobilePhone()) ?
                        String.valueOf(rpcUserInfoVO.getMobilePhone()) : FlowCustomNodeTitleEnum.USER_MOBILE.getName());
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.DATE_TIME.getName())) {
                resultList.add(getSimpleDateFormat(CUR_TIME).format(new Date()));
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.DATE.getName())) {
                resultList.add(getSimpleDateFormat(CUR_DATE).format(new Date()));
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.MONTH.getName())) {
                int month = getCalendar().get(Calendar.MONTH) + 1;
                resultList.add(month + "");
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.YEAR.getName())) {
                resultList.add(String.valueOf(getCalendar().get(Calendar.YEAR)));
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.DAY.getName())) {
                resultList.add(String.valueOf(getCalendar().get(Calendar.DATE)));
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.WEEK.getName())) {
                resultList.add(String.format("第%s周", getCalendar().get(Calendar.WEEK_OF_YEAR)));
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.QUARTER.getName())) {
                int month = getCalendar().get(Calendar.MONTH) + 1;
                int quarter = month % 3 == 0 ? month / 3 : month / 3 + 1;
                resultList.add(quarter + "");
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.UUID.getName())) {
                resultList.add(UUIDGenerator.generate());
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.DEPARTMENT_FULL_ID.getName())) {
                resultList.add(FlowCustomNodeTitleEnum.DEPARTMENT_FULL_ID.getName());
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.DEPARTMENT_FULL_NAME.getName())) {
                resultList.add(FlowCustomNodeTitleEnum.DEPARTMENT_FULL_NAME.getName());
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.DEPARTMENT_ID.getName())) {
                resultList.add(FlowCustomNodeTitleEnum.DEPARTMENT_ID.getName());
            } else if (Objects.equals(exp, FlowCustomNodeTitleEnum.DEPARTMENT_NAME.getName())) {
                resultList.add(FlowCustomNodeTitleEnum.DEPARTMENT_NAME.getName());
            } else {
                String customExp = trimExpression(exp);
                customExp = analysisCustomExpression(customExp, variableContainer);

                resultList.add(customExp);
            }
        }
        return StringUtils.join(resultList, "");
    }


    private String analysisCustomExpression(String customExp, VariableContainer variableContainer) {
        if (ExpressionUtils.isExpression(customExp)) {
            try {
                Object expressValue = null;
                ExpressionCmd expressionCmd = new ExpressionCmd(customExp,variableContainer);
                expressValue = managementService.executeCommand(expressionCmd);
                if (Objects.nonNull(expressValue)) {
                    customExp = expressValue.toString();
                }
            } catch (Exception e) {
                log.warn("自定义表达式：{} 函数解析失败：{}", customExp, e.getMessage());
            }
        }
        return customExp;
    }

    private SimpleDateFormat getSimpleDateFormat(String format) {
        return new SimpleDateFormat(format);
    }

    private Calendar getCalendar() {
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(new Date());
        return calendar;
    }

    private boolean verificationString(String str) {
        if (str == null || str.isEmpty()) {
            return false;
        } else {
            return true;
        }
    }

    private boolean isExpression(String source) {
        String expressionPrefix = "@{";
        String expressionSuffix = "}";
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(source) && source.startsWith(expressionPrefix) && source.endsWith(expressionSuffix)) {
            return true;
        }
        return false;
    }

    /**
     * 获取表达式内容，@{expression} => expression
     *
     * @param source
     * @return
     */
    private String trimExpression(String source) {
        if (isExpression(source)) {
            return source.substring(2, source.length() - 1);
        }
        return source;
    }


    @Override
    public void analysisTitleExpression(TaskEntity taskEntity) {
        //流程实例id
        String processInstanceId = taskEntity.getProcessInstanceId();
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(taskEntity.getProcessDefinitionId());
        //部署id
        String deployId = processDefinition.getDeploymentId();
        //节点编码
        String activityId = taskEntity.getTaskDefinitionKey();
        //拟稿人
        String initiatorId = taskEntity.getVariable("assigned_apply_initiator").toString();


        //标题表达式
        FlowTitleExpression flowTitleExpression = flowTitleExpressionDAO.getFlowTitleExpressionByDeployIdAndActivityId(deployId, activityId);
        if (Objects.isNull(flowTitleExpression)){
            flowTitleExpression = flowTitleExpressionDAO.getFlowGlobalTitleExpressionByDeployId(deployId);
        }
        if (!Objects.isNull(flowTitleExpression)) {
            FlowTitleExpressionResult flowTitleExpressionResult = new FlowTitleExpressionResult();
            flowTitleExpressionResult.setDeployId(deployId);
            flowTitleExpressionResult.setActivityId(activityId);
            flowTitleExpressionResult.setResult(expressionResult(flowTitleExpression.getExpression(), getUserInfoVO(initiatorId), taskEntity));
            flowTitleExpressionResult.setProcessInstanceId(processInstanceId);
            flowTitleExpressionResultDAO.insertTitleExpressionResult(flowTitleExpressionResult);
        }
    }


    private RpcUserInfoVO getUserInfoVO(String initiatorId) {
        //用户数据
        SelectUserInfoReqVO selectUserInfoReqVO = new SelectUserInfoReqVO();
        selectUserInfoReqVO.setUserId(Long.parseLong(initiatorId));
        BaseResult<RpcUserInfoVO> result = userFeignService.qryUserInfo(selectUserInfoReqVO);
        RpcUserInfoVO rpcUserInfoVO = result.getData();
        return rpcUserInfoVO;
    }


}
